//compile command:g++ main.cpp -o realserver2 -lmysqlclient -I/usr/include/mysql/ -L/usr/lib/mysql -lpthread -o pthread
#include<fstream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<iostream>
#include <mysql.h>
#include <time.h>
#include<vector>
#include<map>
#define SERVER_PORT 60000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
using namespace std;
struct playerdata
{
    int id;
    string username;
    int win;
    int lose;
    int online;
    string password;
};
map<string,int> n2c;//name2clientidofsitu username转换clientid的位置
map<int,string> c2n;//clientidofsitu2name clientid的位置转换username
map<string,int> n2g;//username2gamenumber username转换gamenumber
vector<int> clientids;
map<int,pthread_t> c2pt;//clientidsitu2pthread_t clientid位置转换pthread_t
vector<pthread_t> ptharr;//pthread_t 的数组
vector<playerdata> apd;
vector<string> yarr;
int totalyarr;
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
char server[] = "localhost";
char user[] = "root";
char password[] = "root"; /* 此处改成你的密码 */
char database[] = "points24db";/*你的数据库名字，比如studentDB*/
bool islogin(string str)
{
    string s="login";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool isinvite(string str)
{
    string s="invite";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool iswait(string str)
{
    string s="wait";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool isaccinvite(string str)
{
    string s="accinvite";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool isplayingwin(string str)
{
    string s="playingwin";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool isregister(string str)
{
    string s="register";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1; 
}
bool isplayingwait(string str)
{
    string s="playingwait";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool isrealuser(string str,int n)
{
    string username,password;
    for(int i=6;i<27;i++)
    {
        if(str[i]==' ')break;
        username+=str[i];
    }
    for(int i=26;i<47;i++)
    {
        if(str[i]==' ')break;
        password+=str[i];
    }
    for(int i=0;i<apd.size();i++)
    {
        if(username==apd[i].username&&password==apd[i].password)
        {
            n2c[username]=n;
            c2n[n]=username;
            return 1;
        }
    }
    cout<<username<<"----cannot_find-----"<<password<<endl;
    return 0;
}
bool isrefresh(string str)
{
    string s="refresh";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
bool isrank(string str)
{
    string s="rank";
    for(int i=0;i<s.size();i++)
    {
        if(str[i]!=s[i])
        {
            return 0;
        }
    }
    return 1;
}
void invitesb(string str,string myself)
{
    string username;
    for(int i=6;i<str.size();i++)
    {
        username+=str[i];
    }
    int theotheronecid=clientids[n2c[username]];
    string sendbuf="invite"+myself;
    sendbuf+='\r';
    cout<<username<<"==invitesb==="<<theotheronecid<<"===="<<myself<<endl;
    send(theotheronecid,sendbuf.c_str(),sendbuf.size(),0);//发送邀请信息（含邀请人）
}
void setwaitstatus(string str,int n)
{
    string username;
    /*for(int i=4;i<str.size();i++)
    {
        username+=str[i];
    }*/
    username=c2n[n];
    for(int i=0;i<apd.size();i++)
    {
        if(username==apd[i].username)
        {
            apd[i].online=1;
            break;
        }
    }
    cout<<username<<"--------"<<endl;
}
double getresult(double a,double b,int c)
{
    if(c==1)return a+b;
    else if(c==2)return a-b;
    else if(c==3)return a*b;
    else return a/b;
}
/*bool is24result(vector<int> arr)
{
    double result[200];//递归有风险 这里就不递归了 蠢一点：）
    double num[4];
    for(int i=0;i<4;i++)
    {
        num[i]=arr[i];
    }
    result[0]=num[0]+num[1]+num[2]+num[3];
    result;
}*/
string getrand()
{
    string str="y";
    srand((unsigned)time(NULL)); 
    int num=0;
    vector<int> v;
    num=(rand()%totalyarr);
    str=yarr[num];
    str+='\r';
    //str="y03,08,01,00\n";
    return str;
}
vector<vector<int> > games;///0 player1win;1 player2win;2 p1ready;3 p2ready;4 p1clientid;5 p2clientid;
void* gamerunning(void* local)
{
    int gn=*((int*)local);
    cout<<"gamerunnign lalalalla"<<gn<<endl;
    for(int i=0;i<4;i++)games[gn][i]=0;
    string lose="lose\n";
    string k="k\n";
    send(clientids[games[gn][4]],k.c_str(),k.length(),0);
    //send(clientids[games[gn][5]],k.c_str(),3,0);
    while(1)
    {
        if(games[gn][6])
        break;
        if(games[gn][0])
        {
            send(clientids[games[gn][5]],lose.c_str(),lose.length(),0);//发给对方输了
            games[gn][0]=0;
        }
        else if(games[gn][1])
        {
            send(clientids[games[gn][4]],lose.c_str(),lose.length(),0);//发给对方输了
            games[gn][1]=0;
        }
        if(games[gn][2]&&games[gn][3])
        {
            string s=getrand();
            send(clientids[games[gn][4]],s.c_str(),s.length(),0);
            send(clientids[games[gn][5]],s.c_str(),s.length(),0);
            games[gn][2]=games[gn][3]=0;
        }
        //cout<<clientids[games[gn][4]]<<"clientids check"<<clientids[games[gn][5]]<<endl;
    }
    pthread_exit(NULL);
}
void startplayin(string str,int n)
{
    cout<<"accept了我叼你妈的"<<endl;
    string username;//send invite player的username
    for(int i=9;i<str.size();i++)
    {
        username+=str[i];
    }
    cout<<"username:"<<username<<endl;
    int cid=clientids[n2c[username]];
    string accepttext="accept\r";
    send(cid,accepttext.c_str(),7,0);
    string jieshouname=c2n[n];//接受邀请玩家的username
    cout<<"jieshouname:"<<jieshouname<<endl;
    int kj=0;
    for(int i=0;i<apd.size();i++)
    {
        if(kj==2)break;
        if(username==apd[i].username||jieshouname==apd[i].username)
        {
            //apd[i].online=2;
            kj++;
        }
    }
    pthread_t *pid=new pthread_t;
    //ptharr.push_back(pid);
    int b=ptharr.size()-1;
    vector<int> v;
    v.resize(7);
    games.push_back(v);
    int gamesizejian1=games.size()-1;
    games[gamesizejian1][4]=n2c[jieshouname];
    games[gamesizejian1][5]=n2c[username];
    games[gamesizejian1][6]=0;
    int gamenumber=gamesizejian1;
    n2g[username]=gamenumber;
    n2g[jieshouname]=gamenumber;
    cout<<"gamesizejian1 : "<<gamesizejian1<<endl;
    if(pid==NULL)cout<<"worichuangjianchenggonglalalallanimabikkongde"<<endl;
    pthread_create(pid,NULL,gamerunning,&gamenumber);
    cout<<"chuangjianchenggonglalalalla"<<endl;
    //pthread_create(&ptharr[b],NULL,gamerunning,&gamenumber); //感觉不能同步
    //return gamenumber;
}
void playingwin(string str,int n)
{
    int gamenumber=n2g[str];
    if(games[gamenumber][4]==n) games[gamenumber][0]=1;
    else games[gamenumber][1]=1;
}
void playingwait(string str,int n)
{
    int gamenumber=n2g[str];
    cout<<str<<"de gamenumber is"<<gamenumber<<endl;
    if(games[gamenumber][4]==n) games[gamenumber][2]=1;
    else games[gamenumber][3]=1;
}
void getrank(string str,int n)
{
    string s="";
    for(int i=0;i<apd.size();i++)
    {
        s+=apd[i].username;
        s+=',';
        int t=apd[i].win;char c=0;
        if(t==0)s+='0';
        while(t>0)
        {
            c=t%10;
            t/=10;
            s+=(c+'0');
        }
        s+=',';
        t=apd[i].lose;
        if(t==0)s+='0';
        while(t>0)
        {
            c=t%10;
            t/=10;
            s+=(c+'0');
        }
        s+=';';
    }
    s+='\r';
    send(clientids[n],s.c_str(),s.size(),0);
    cout<<s<<endl;
}
void sbregister(string str,int n)
{
    playerdata a;
    a.id=0;
    a.username="";
    int strlen=str.length();
    int p=0;
    for(int i=8;i<strlen;i++)
    {
        if(str[i]==';')
        {p=i+1;break;}
        else a.username+=str[i];
    }
    a.password="";
    for(int i=p;i<strlen;i++)
    {
        a.password+=str[i];
    }
    a.win=0;a.lose=0;a.online=0;
    apd.push_back(a);
    string operation="INSERT INTO points24( id, user,win,lose,password) VALUES ( ";
    operation+=(a.id+'0');
    operation+=',';
    operation+="\"";
    operation+=a.username;
    operation+="\"";
    operation+=',';
    operation+="0,0,\"";
    operation+=a.password;
    operation+="\")";
    //2,\"egg1\",21312,23,0,\"123456\");";
    conn = mysql_init(NULL);
    /* Connect to database */
    if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }
    if(mysql_query(conn,operation.c_str())!=0)
    {
        printf("something is wrong!\n");
        return ;
    }
    string regyes="regyes\r";
    send(clientids[n],regyes.c_str(),regyes.length(),0);
}
void* clientListenLoop(void* num)
{
    char buf[BUFFER_SIZE];
    string username="";
    int n=*(int*)num;
    cout<<"n="<<n<<endl;
    int clientid=clientids[n];
    cout<<"clientid="<<clientid<<endl;
    int gamenumber=-1;
    while(1)
    {
        memset(buf,0x00,sizeof(buf));
        int len=recv(clientid,buf,BUFSIZ,0);
        /*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数，send返回发送的字节数*/
        if(len==0||len==1)break;
        cout<<buf<<endl;
        if(islogin(buf))
        {
            //if(1)
            if(isrealuser(buf,n))//没测试
            {
                for(int i=6;i<27;i++)
                {
                    if(buf[i]==' ')break;
                    username+=buf[i];
                }
                string y="y\r";
                send(clientid,y.c_str(),y.size(),0);
                string list="onlinelist:";
                for(int i=0;i<apd.size();i++)
                {
                    if(apd[i].online!=0&&apd[i].username!=username)
                    {
                        list+=apd[i].username;
                        /*if(apd[i].online==1)list+='1';//在线状态
                        else list+='2';*/
                        list+=',';
                    }
                }
                list+='\r';
                send(clientid,list.c_str(),list.size(),0);
            }
        }
        else if(isrefresh(buf))
        {
            string list="onlinelist:";
            for(int i=0;i<apd.size();i++)
            {
                if(apd[i].online!=0&&apd[i].username!=username)
                {
                    list+=apd[i].username;
                    /*if(apd[i].online==1)list+='1';//在线状态
                    else list+='2';*/
                    list+=',';
                }
            }
            list+='\r';
            send(clientid,list.c_str(),list.size(),0);
        }
        else if(isregister(buf))
        {
            sbregister(buf,n);
        }
        else if(isrank(buf))
        {
            getrank(buf,n);
        }
        else if(isinvite(buf))
        {
            invitesb(buf,c2n[n]);
        }
        else if(iswait(buf))
        {
            setwaitstatus(buf,n);
        }
        else if(isaccinvite(buf))
        {
            startplayin(buf,n);
        }
        else if(isplayingwin(buf))
        {
            playingwin(username,n);
        }
        else if(isplayingwait(buf))
        {
            playingwait(username,n);
        }
    }
    if(gamenumber!=-1)
    games[gamenumber][6]=1;
    for(int i=0;i<apd.size();i++)
    {
        if(username==apd[i].username)
        {apd[i].online=0;break;}
    }
    pthread_exit(NULL);
}
void allplayerdatainit()
{
    games.resize(5);//i dont know why 
    conn = mysql_init(NULL);
    /* Connect to database */
    if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }
    if (mysql_query(conn, "show tables")) {
      fprintf(stderr, "%s\n", mysql_error(conn));
      exit(1);
    }
    res = mysql_use_result(conn);
    /* output table name */
    printf("MySQL Tables in points24db database:\n");
    while ((row = mysql_fetch_row(res)) != NULL)
    {printf("%s \n", row[0]);}

    if (mysql_query(conn, "select * from points24")) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }
    //MYSQL_RES *result = NULL;
	int num_rows = 0,num_fields = 0;
	res = mysql_store_result(conn);//获取查询结果

	num_rows=mysql_num_rows(res);//行
	num_fields=mysql_num_fields(res);//列
 
	row = NULL;
	//读取数据
    int kk=0;
	while(1)
	{
		row = mysql_fetch_row(res);
		//直到数据为空
		if(row==NULL) break;
		playerdata p=*(new playerdata);//可能会有大bug
        p.id=0;
        p.win=0;
        p.lose=0;
        p.online=0;
        p.username="";
        p.password="";
        //p.id=(int)row[0];
        // for(int i=0;i<strlen((char *)row[0]);i++)
        //printf("%d\n",strlen((char *)row[0]));
        for(int i=strlen((char *)row[0])-1;i>=0;i--)
        {
            p.id+=row[0][i]-'0';
            p.id*=10;
        }p.id/=10;
        p.username=row[1];
        //p.win=(int)row[2];
        //p.lose=(int)row[3];
        string s=row[2];
        for(int i=s.length()-1;i>=0;i--)
        {
            p.win+=row[2][i]-'0';
            p.win*=10;
        }p.win/=10;
        s=row[3];
        for(int i=s.length()-1;i>=0;i--)
        {
            p.lose+=row[3][i]-'0';
            p.lose*=10;
        }p.lose/=10;
        // if(row[4]=="1")p.online=1;
        // else p.online=0;
        p.online=0;
        p.password=row[4];
        apd.push_back(p);
        kk++;
	}
    /*while(1)
	{
		row = mysql_fetch_row(res);
		//直到数据为空
		if(row==NULL) break;
        for(int i=0; i<num_fields; i++)
		{
			printf("%s ",row[i]);
		}
        printf("\n");
    }*/
    for(int i=0;i<apd.size();i++)
    {
        printf("%d %s %d %d %d %s\n",apd[i].id,apd[i].username.c_str(),apd[i].win,apd[i].lose,apd[i].online,apd[i].password.c_str());
    }
    /* close connection */
    mysql_free_result(res);
    mysql_close(conn);
}
void readmidin()
{
    ifstream infile; 
    infile.open("mid.in");
    string s;
    while(getline(infile,s))
    {
        yarr.push_back(s);
    }
    infile.close();
    infile.clear();
    totalyarr=yarr.size()-2;
    cout<<"totalyarr : "<<totalyarr<<endl;
}
int main()
{
    allplayerdatainit();//apd[0].online=1;
    readmidin();
    int server_sockfd;//服务器端套接字
    int len;
    struct sockaddr_in my_addr;   //服务器网络地址结构体
    struct sockaddr_in remote_addr = {0}; //客户端网络地址结构体
    socklen_t sin_size;
    memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零
    my_addr.sin_family=AF_INET; //设置为IP通信
    my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
    my_addr.sin_port=htons(SERVER_PORT); //服务器端口号
    /*创建服务器端套接字--IPv4协议，面向连接通信，TCP协议*/
    if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
    {
        perror("socket");
        return 1;
    }
    /*将套接字绑定到服务器的网络地址上*/
    if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
    {
        perror("bind");
        return 1;
    }
    /*监听连接请求--监听队列长度为20*/
    listen(server_sockfd,20);
    sin_size=sizeof(struct sockaddr_in);
    while(1)
    {
        clientids.push_back(0);
        /*等待客户端连接请求到达*/
        if((clientids[clientids.size()-1]=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0)
        {
            perror("accept");
            return 1;
        }
        pthread_t tid;
        ptharr.push_back(tid);
        printf("accept client %s\n",inet_ntoa(remote_addr.sin_addr));
        //len=send(clientids.size()-1,"Welcome to my server\n",21,0);//发送欢迎信息
        int a=clientids.size()-1;//clientid的位置
        pthread_create(&ptharr[ptharr.size()-1],NULL,clientListenLoop,&a);
        c2pt[a]=ptharr.size()-1;
    }
    return 0;
} 